/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.freedom.railhunter.main;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import org.apache.commons.lang3.StringUtils;
import org.freedom.railhunter.exception.LoginFailedException;
import org.freedom.railhunter.exception.SessionExpiredException;
import org.freedom.railhunter.exception.SubmitFailedException;
import org.freedom.railhunter.model.LeftTicketItem;
import org.freedom.railhunter.model.Passenger;
import org.freedom.railhunter.model.Order;
import org.freedom.railhunter.model.OrderConfiguration;
import org.freedom.railhunter.model.Purpose;
import org.freedom.railhunter.model.QueueCount;
import org.freedom.railhunter.model.SeatType;
import org.freedom.railhunter.model.Station;
import org.freedom.railhunter.model.SubmitOrderResult;
import org.freedom.railhunter.service.BaseService;
import org.freedom.railhunter.service.CookieService;
import org.freedom.railhunter.service.LoginService;
import org.freedom.railhunter.service.PassengerService;
import org.freedom.railhunter.service.RandCodeService;
import org.freedom.railhunter.service.TicketService;
import org.freedom.railhunter.ui.PassengersSeleter;
import org.freedom.railhunter.ui.RandCodeDialog;
import org.freedom.railhunter.ui.component.CloseableLabelContainer;
import org.freedom.railhunter.util.Des;
import org.freedom.railhunter.util.MessageConsole;
import org.freedom.railhunter.util.StationManager;
import org.freedom.railhunter.util.UUWiseHelper;
import org.freedom.railhunter.util.mail.MailSenderInfo;
import org.freedom.railhunter.util.mail.SimpleMailSender;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Alan
 */
public class MainFrame extends javax.swing.JFrame {
    
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MainFrame.class);
    
    private boolean hasLoginUUW = false;
    
    private Passenger[] allPassengers;
    
    private boolean orderSuccess;
    
    private ScheduledExecutorService scheduExec;
    
    private static String IDLE = "Idle";

    private static String WAIT = "WAIT";
    
    private String fillRandCodeStatus = IDLE;
    
    private static final String  FILL_RAND_CODE_STATUS_NAME = "fillRandCodeStatus";
    
    private byte[] currentBandImg;
    
    private String currentRandCode;
    
    private String loginUsername;
    
    /**
     * Creates new form MainFrame
     */
    public MainFrame(String username) {
        loginUsername = username;
        this.setTitle("SnowWolf-" + loginUsername);
        this.setIconImage(new ImageIcon(getClass().getResource("/img/snow_wolf.jpg")).getImage());
        initComponents();
        loadProperties();
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });
        //  后台自动加载联系人
        new SwingWorker<Passenger[], Void>(){
            @Override
            protected Passenger[] doInBackground() throws Exception {
                PassengerService passengerService = PassengerService.getInstance();
                Passenger[] passengers = passengerService.getNoramlPassengers(CookieService.getInstance().getCookieData());
                return passengers;
            }
            
            @Override
            protected void done() {
                try {
                    setAllPassengers(get());
                } catch (InterruptedException | ExecutionException ex) {
                    logger.error("", ex);
                }
            }
        }.execute();
        
        if (autoFillBandCodeCheckBox.isSelected()) {
            final String uuwUsername = uuwUsernameField.getText();
            final String uuwPassword = new String(uuwPasswordField.getPassword());
            if (StringUtils.isNotEmpty(uuwUsername)
                    && StringUtils.isNotEmpty(uuwPassword)) {
                new SwingWorker<Boolean, Void>() {
                    @Override
                    protected Boolean doInBackground() throws Exception {
                        // 登录到uu云
                        try {
                            UUWiseHelper.initAndLogin(uuwUsername, uuwPassword);
                            hasLoginUUW = true;
                            uuwStatusLabel.setText("已登录");
                        } catch (Exception e) {
                        }
                        return true;
                    }
                }.execute();
            }
        }
        
        MessageConsole mc = new MessageConsole(consoleArea);
        mc.redirectOut();
        mc.redirectErr(Color.black, null);
        mc.setMessageLines(100);
        
        new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dateLabel.setText(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            }
        }).start();
        
        this.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals(FILL_RAND_CODE_STATUS_NAME)) {
                    if (WAIT.equals(fillRandCodeStatus) && getCurrentBandImg() != null) {
                        RandCodeDialog randCodeDialog = new RandCodeDialog(MainFrame.this, true, getCurrentBandImg());
                        randCodeDialog.setLocationRelativeTo(MainFrame.this);
                        randCodeDialog.setVisible(true);
                        String randCode = randCodeDialog.getRandCode();
                        setCurrentRandCode(randCode);
                        fillRandCodeStatus = IDLE;
                    }
                }
            }
        });
    }

    public Passenger[] getAllPassengers() {
        return allPassengers;
    }

    public synchronized void setAllPassengers(Passenger[] allPassengers) {
        this.allPassengers = allPassengers;
    }

    private void loadProperties() {
        OrderConfiguration configuration = OrderConfiguration.getInstance();
        Station fromStation  = configuration.getFromStation();
        Station toStation = configuration.getToStation();
        fromStaionField.setText(fromStation == null ? "" : fromStation.getName());
        toStationField.setText(toStation == null ? "" : toStation.getName());
        trainDateChooser.setDate(configuration.getTrainDate());
        ((CloseableLabelContainer<String>)passengersContainer).addElements(configuration.getPassengers());
        ((CloseableLabelContainer<String>)trainCodesContainer).addElements(configuration.getTrainCodeList());
        ((CloseableLabelContainer<SeatType>)seatTypesContainer).addElements(configuration.getSeatTypeList());
        uuwUsernameField.setText(configuration.getUuwiseUsername());
        try {
            uuwPasswordField.setText(Des.decrypt(configuration.getUuwisePassword()));
        } catch (Exception ex) {
            logger.error("", ex);
        }
        autoFillBandCodeCheckBox.setSelected(configuration.isAutoFillBandCode());
        
        mailSenderUsernameField.setText(configuration.getMailSenderUsername());
        try {
            mailSenderPasswordField.setText(Des.decrypt(configuration.getMailSenderPassword()));
        } catch (Exception ex) {
            logger.error("", ex);
        }
        mailSenderServerHostField.setText(configuration.getMailSenderServerHost());
        mailSenderServerPortField.setText(configuration.getMailSenderServerPort());
        mailRecipientUsernameField.setText(configuration.getMailRecipientUsername());
    }
    
    private void saveProperties() {
        OrderConfiguration configuration = OrderConfiguration.getInstance();
        Properties orderConfigProps = configuration.getOrderConfigProps();
        orderConfigProps.setProperty(OrderConfiguration.FROM_STATION_NAME_KEY, fromStaionField.getText());
        orderConfigProps.setProperty(OrderConfiguration.TO_STATION_NAME_KEY, toStationField.getText());
        orderConfigProps.setProperty(OrderConfiguration.TRAIN_DATE_KEY, 
                BaseService.yyyy_mm_dd_format.format(trainDateChooser.getCalendar().getTime()));
        orderConfigProps.setProperty(OrderConfiguration.PASSENGERS_KEY, ((CloseableLabelContainer)passengersContainer).getElementsString());
        orderConfigProps.setProperty(OrderConfiguration.TRAIN_CODES_KEY, ((CloseableLabelContainer)trainCodesContainer).getElementsString());
        orderConfigProps.setProperty(OrderConfiguration.SEAT_TYPES_KEY, ((CloseableLabelContainer)seatTypesContainer).getElementsString());
        orderConfigProps.setProperty(OrderConfiguration.UUWISE_USERNAME_KEY, uuwUsernameField.getText());
        try {
            orderConfigProps.setProperty(OrderConfiguration.UUWISE_PASSWORD_KEY,
                    Des.encrypt(new String(uuwPasswordField.getPassword())));
        } catch (Exception ex) {
            logger.error("", ex);
        }
        orderConfigProps.setProperty(OrderConfiguration.AUTO_FILL_BAND_CODE_KEY, String.valueOf(autoFillBandCodeCheckBox.isSelected()));
        
        orderConfigProps.setProperty(OrderConfiguration.MAIL_SENDER_USERNAME, mailSenderUsernameField.getText().trim());
        try {
            orderConfigProps.setProperty(OrderConfiguration.MAIL_SENDER_PASSWORD, Des.encrypt(new String(mailSenderPasswordField.getPassword())));
        } catch (Exception ex) {
            logger.error("", ex);
        }
        orderConfigProps.setProperty(OrderConfiguration.MAIL_SENDER_SERVER_HOST, mailSenderServerHostField.getText().trim());
        orderConfigProps.setProperty(OrderConfiguration.MAIL_SENDER_SERVER_PORT, mailSenderServerPortField.getText().trim());
        orderConfigProps.setProperty(OrderConfiguration.MAIL_RECIPIENT_USERNAME, mailRecipientUsernameField.getText().trim());
        configuration.storeOrderConfig();
    }
    
    private void exit() {
        this.setVisible(false);
        try {
            // logout
            LoginService loginService = LoginService.getInstance();
            loginService.logout(CookieService.getInstance().getCookieData());
            // save properties
            saveProperties();
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        } finally {
            System.exit(0);
        }
    }

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT
     * modify this code. The content of this method is always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        buttonGroup = new javax.swing.ButtonGroup();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        fromStaionField = new javax.swing.JTextField();
        toStationField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        trainHighPriorityButton = new javax.swing.JRadioButton();
        seatHighPriorityButton = new javax.swing.JRadioButton();
        addPassengerButton = new javax.swing.JButton();
        addTrainCodeButton = new javax.swing.JButton();
        addSeatTypeButton = new javax.swing.JButton();
        stopButton = new javax.swing.JButton();
        trainDateChooser = new com.toedter.calendar.JDateChooser();
        startButton = new javax.swing.JButton();
        passengersContainer = new org.freedom.railhunter.ui.component.CloseableLabelContainer<>(new ArrayList<String>());
        jLabel14 = new javax.swing.JLabel();
        trainCodesContainer = new org.freedom.railhunter.ui.component.CloseableLabelContainer<>(new ArrayList<String>());
        jLabel13 = new javax.swing.JLabel();
        seatTypesContainer = new org.freedom.railhunter.ui.component.CloseableLabelContainer<>(new ArrayList<SeatType>());
        jLabel15 = new javax.swing.JLabel();
        autoFillBandCodeCheckBox = new javax.swing.JCheckBox();
        jPanel3 = new javax.swing.JPanel();
        mailSenderUsernameField = new javax.swing.JTextField();
        jLabel8 = new javax.swing.JLabel();
        jLabel11 = new javax.swing.JLabel();
        jLabel12 = new javax.swing.JLabel();
        mailSenderServerHostField = new javax.swing.JTextField();
        jLabel16 = new javax.swing.JLabel();
        mailSenderServerPortField = new javax.swing.JTextField();
        mailTestButton = new javax.swing.JButton();
        jLabel17 = new javax.swing.JLabel();
        mailRecipientUsernameField = new javax.swing.JTextField();
        mailSenderPasswordField = new javax.swing.JPasswordField();
        jPanel2 = new javax.swing.JPanel();
        jLabel9 = new javax.swing.JLabel();
        uuwUsernameField = new javax.swing.JTextField();
        jLabel10 = new javax.swing.JLabel();
        uuwPasswordField = new javax.swing.JPasswordField();
        login2UUWButton = new javax.swing.JButton();
        uuwStatusLabel = new javax.swing.JLabel();
        outputPane = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        consoleArea = new javax.swing.JTextArea();
        progressBar = new javax.swing.JProgressBar();
        dateLabel = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("预定配置"));

        jLabel1.setText("出发地");

        jLabel2.setText("目的地");

        jLabel3.setText("乘车人");

        jLabel4.setText("优先车次");

        jLabel5.setText("出发日");

        jLabel6.setText("优先席别");

        buttonGroup.add(trainHighPriorityButton);
        trainHighPriorityButton.setSelected(true);
        trainHighPriorityButton.setText("车次优先 ");

        buttonGroup.add(seatHighPriorityButton);
        seatHighPriorityButton.setText("席别优先");

        addPassengerButton.setText("添加");
        addPassengerButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addPassengerButtonActionPerformed(evt);
            }
        });

        addTrainCodeButton.setText("添加");
        addTrainCodeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addTrainCodeButtonActionPerformed(evt);
            }
        });

        addSeatTypeButton.setText("添加");
        addSeatTypeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addSeatTypeButtonActionPerformed(evt);
            }
        });

        stopButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/stop.png"))); // NOI18N
        stopButton.setText("停止刷票");
        stopButton.setEnabled(false);
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        startButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/start.png"))); // NOI18N
        startButton.setText("开始刷票");
        startButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });

        passengersContainer.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        passengersContainer.setPreferredSize(new java.awt.Dimension(4, 35));
        passengersContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel14.setText(" ");
        passengersContainer.add(jLabel14);

        trainCodesContainer.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        trainCodesContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel13.setText(" ");
        trainCodesContainer.add(jLabel13);

        seatTypesContainer.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        seatTypesContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));

        jLabel15.setText(" ");
        seatTypesContainer.add(jLabel15);

        autoFillBandCodeCheckBox.setText("自动填入验证码");
        autoFillBandCodeCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                autoFillBandCodeCheckBoxActionPerformed(evt);
            }
        });

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("邮件设置"));

        jLabel8.setText("登录邮箱");

        jLabel11.setText("登录密码");

        jLabel12.setText("SMTP服务器");

        jLabel16.setText("端口");

        mailTestButton.setText("测试");
        mailTestButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mailTestButtonActionPerformed(evt);
            }
        });

        jLabel17.setText("收件人");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel8)
                            .addComponent(jLabel11)))
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addComponent(jLabel12))
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jLabel17)))
                .addGap(18, 18, 18)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(mailSenderPasswordField)
                    .addComponent(mailSenderUsernameField)
                    .addComponent(mailSenderServerHostField)
                    .addComponent(mailRecipientUsernameField))
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addGap(18, 18, 18)
                        .addComponent(jLabel16)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(mailSenderServerPortField, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(mailTestButton)
                        .addContainerGap())))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(mailSenderUsernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel8))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel11)
                    .addComponent(mailSenderPasswordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel12)
                    .addComponent(mailSenderServerHostField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel16)
                    .addComponent(mailSenderServerPortField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel17)
                    .addComponent(mailRecipientUsernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(mailTestButton))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(autoFillBandCodeCheckBox)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 280, Short.MAX_VALUE)
                                .addComponent(startButton)
                                .addGap(18, 18, 18)
                                .addComponent(stopButton))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(trainHighPriorityButton)
                                .addGap(18, 18, 18)
                                .addComponent(seatHighPriorityButton)
                                .addGap(0, 0, Short.MAX_VALUE))
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                                .addComponent(fromStaionField, javax.swing.GroupLayout.DEFAULT_SIZE, 139, Short.MAX_VALUE)
                                .addGap(18, 18, 18)
                                .addComponent(jLabel2)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(toStationField, javax.swing.GroupLayout.DEFAULT_SIZE, 141, Short.MAX_VALUE)
                                .addGap(18, 18, 18)
                                .addComponent(jLabel5)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(trainDateChooser, javax.swing.GroupLayout.DEFAULT_SIZE, 226, Short.MAX_VALUE))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(passengersContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(trainCodesContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(seatTypesContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(addTrainCodeButton, javax.swing.GroupLayout.Alignment.TRAILING)
                                    .addComponent(addPassengerButton, javax.swing.GroupLayout.Alignment.TRAILING)
                                    .addComponent(addSeatTypeButton, javax.swing.GroupLayout.Alignment.TRAILING))))))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(15, 15, 15)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE, false)
                        .addComponent(fromStaionField)
                        .addComponent(jLabel1)
                        .addComponent(jLabel2)
                        .addComponent(toStationField)
                        .addComponent(jLabel5))
                    .addComponent(trainDateChooser, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(passengersContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel3)
                    .addComponent(addPassengerButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jLabel4)
                    .addComponent(trainCodesContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(addTrainCodeButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jLabel6)
                    .addComponent(seatTypesContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(addSeatTypeButton))
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(trainHighPriorityButton)
                    .addComponent(seatHighPriorityButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(stopButton)
                    .addComponent(startButton)
                    .addComponent(autoFillBandCodeCheckBox))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 27, Short.MAX_VALUE)
                .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("自动填入验证码"));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jPanel2, org.jdesktop.beansbinding.BeanProperty.create("enabled"), "");
        bindingGroup.addBinding(binding);

        jLabel9.setText("优优云账号：");

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel9, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), uuwUsernameField, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        jLabel10.setText("优优云密码：");

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel10, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), uuwPasswordField, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        uuwPasswordField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                uuwPasswordFieldActionPerformed(evt);
            }
        });

        login2UUWButton.setText(" 登录到优优云");

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), login2UUWButton, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        login2UUWButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                login2UUWButtonActionPerformed(evt);
            }
        });

        uuwStatusLabel.setFont(new java.awt.Font("宋体", 3, 12)); // NOI18N
        uuwStatusLabel.setText("未登录");

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, autoFillBandCodeCheckBox, org.jdesktop.beansbinding.ELProperty.create("${selected}"), uuwStatusLabel, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jLabel9, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jLabel10, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(uuwUsernameField)
                    .addComponent(uuwPasswordField, javax.swing.GroupLayout.DEFAULT_SIZE, 224, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(login2UUWButton)
                    .addComponent(uuwStatusLabel))
                .addContainerGap(274, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel9)
                    .addComponent(uuwUsernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(uuwStatusLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel10)
                    .addComponent(uuwPasswordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(login2UUWButton))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        outputPane.setBorder(javax.swing.BorderFactory.createTitledBorder("输出"));
        outputPane.setLayout(new java.awt.BorderLayout());

        consoleArea.setColumns(20);
        consoleArea.setRows(5);
        jScrollPane1.setViewportView(consoleArea);

        outputPane.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        dateLabel.setText("2014-01-20 21:53:00");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(outputPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(dateLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(outputPane, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(dateLabel))
                .addContainerGap())
        );

        bindingGroup.bind();

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void addPassengerButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addPassengerButtonActionPerformed
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        addPassengerButton.setEnabled(false);
        new SwingWorker<Passenger[], Void>() {
            @Override
            protected Passenger[] doInBackground() throws Exception {
                if (getAllPassengers() != null) {
                    return getAllPassengers();
                }
                PassengerService passengerService = PassengerService.getInstance();
                Passenger[] passengers = passengerService.getNoramlPassengers(CookieService.getInstance().getCookieData());
                return passengers;
            }

            @Override
            protected void done() {
                try {
                    setAllPassengers(get());
                    PassengersSeleter passengersSeleter = new PassengersSeleter(MainFrame.this, true, getAllPassengers());
                    passengersSeleter.setLocationRelativeTo(MainFrame.this);
                    passengersSeleter.setVisible(true);
                    List<Passenger> selectedPassengers = passengersSeleter.getSelectedPassengerList();
                    if (selectedPassengers.isEmpty()) {
                        return;
                    }
                    List<String> selectedPassengerNames = new ArrayList<>();
                    for (Passenger passenger : selectedPassengers) {
                        selectedPassengerNames.add(passenger.getPassengerName());
                    }
                    ((CloseableLabelContainer<String>)passengersContainer).addElements(selectedPassengerNames);
                    MainFrame.this.repaint();
                } catch (InterruptedException | ExecutionException ex) {
                    logger.error("", ex);
                    if (ex.getCause() instanceof SessionExpiredException) {
                        JOptionPane.showMessageDialog(MainFrame.this, "您需要退出并重新登录！", "警告", JOptionPane.WARNING_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(MainFrame.this, "加载联系人失败！", "错误", JOptionPane.ERROR_MESSAGE);
                    }
                } finally {
                    MainFrame.this.setCursor(Cursor.getDefaultCursor());
                    addPassengerButton.setEnabled(true);
                }
            }
        }.execute();
    }//GEN-LAST:event_addPassengerButtonActionPerformed

    private void addTrainCodeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTrainCodeButtonActionPerformed
        String trainCode = JOptionPane.showInputDialog(this, "请输入车次：", "输入", JOptionPane.QUESTION_MESSAGE);
        if (StringUtils.isBlank(trainCode)) {
            return;
        }
        ((CloseableLabelContainer<String>)trainCodesContainer).addElement(trainCode.toUpperCase());
        this.repaint();
    }//GEN-LAST:event_addTrainCodeButtonActionPerformed

    private void addSeatTypeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addSeatTypeButtonActionPerformed
        SeatType selectedSeatType = (SeatType) JOptionPane.showInputDialog(this,
                "请选择一个席别？",
                "选择席别",
                JOptionPane.QUESTION_MESSAGE,
                null,
                SeatType.values(),
                SeatType.YING_WO);
        ((CloseableLabelContainer<SeatType>)seatTypesContainer).addElement(selectedSeatType);
        this.repaint();
    }//GEN-LAST:event_addSeatTypeButtonActionPerformed

    private void login2UUW() {
        login2UUWButton.setEnabled(false);
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        try {
            if (hasLoginUUW) {
                int value = JOptionPane.showConfirmDialog(this, "您已经成功登录，确定要重复登录吗？", "问题", JOptionPane.YES_NO_OPTION);
                if (!(JOptionPane.YES_OPTION == value)) {
                    return;
                }
            }
            String uuwUsername = uuwUsernameField.getText();
            String uuwPassword = new String(uuwPasswordField.getPassword());

            // 登录到uu云
            UUWiseHelper.initAndLogin(uuwUsername, uuwPassword);
            hasLoginUUW = true;
            uuwStatusLabel.setText("已登录");
            JOptionPane.showMessageDialog(this, "登录到优优云成功！", "信息", JOptionPane.INFORMATION_MESSAGE);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, "登录到优优云失败！请检查您的用户名和密码。", "警告", JOptionPane.WARNING_MESSAGE);
        } finally {
            login2UUWButton.setEnabled(true);
            this.setCursor(Cursor.getDefaultCursor());
        }
    }
    
    private void login2UUWButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_login2UUWButtonActionPerformed
        login2UUW();
    }//GEN-LAST:event_login2UUWButtonActionPerformed

    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed
        String fromStaionName = fromStaionField.getText();
        String toStationName = toStationField.getText();
        if (StringUtils.isBlank(fromStaionName) || StringUtils.isBlank(toStationName)) {
            JOptionPane.showMessageDialog(this, "出发地和目的地为必填！", "警告", JOptionPane.WARNING_MESSAGE);
            return;
        }
        Station fromStation = StationManager.NAME_STATION_MAP.get(fromStaionName);
        Station toStation = StationManager.NAME_STATION_MAP.get(toStationName);
        if (fromStation == null || toStation == null) {
            JOptionPane.showMessageDialog(this, "出发地或目的填写错误！", "警告", JOptionPane.WARNING_MESSAGE);
            return;
        }

        if (((CloseableLabelContainer) passengersContainer).getElements().isEmpty()) {
            JOptionPane.showMessageDialog(this, "请添加乘车人！", "警告", JOptionPane.WARNING_MESSAGE);
            return;
        }

        if (autoFillBandCodeCheckBox.isSelected() && !hasLoginUUW) {
            try {
                String uuwUsername = uuwUsernameField.getText();
                String uuwPassword = new String(uuwPasswordField.getPassword());
                // 登录到uu云
                UUWiseHelper.initAndLogin(uuwUsername, uuwPassword);
                hasLoginUUW = true;
                uuwStatusLabel.setText("已登录");
                logger.info("成功登录到UU云。");
            } catch (Exception e) {
                JOptionPane.showMessageDialog(this, "登录到UU云失败！请检查您的用户名和密码。", "警告", JOptionPane.WARNING_MESSAGE);
                return;
            }
        }

        startButton.setEnabled(false);
        stopButton.setEnabled(true);
        addPassengerButton.setEnabled(false);
        addSeatTypeButton.setEnabled(false);
        addTrainCodeButton.setEnabled(false);
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        progressBar.setIndeterminate(true);
        
        // 周期执行
        scheduExec = Executors.newScheduledThreadPool(3);
        scheduExec.scheduleAtFixedRate(new OrderTask(), 0, 4950, TimeUnit.MILLISECONDS);
    }//GEN-LAST:event_startButtonActionPerformed

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
        shutDownTasks();
    }//GEN-LAST:event_stopButtonActionPerformed

    private void uuwPasswordFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_uuwPasswordFieldActionPerformed
       login2UUW();
    }//GEN-LAST:event_uuwPasswordFieldActionPerformed

    private void autoFillBandCodeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_autoFillBandCodeCheckBoxActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_autoFillBandCodeCheckBoxActionPerformed

    private void mailTestButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mailTestButtonActionPerformed
        // 发送邮件
        sendEmail("SnowWolf邮件发送测试", "【" + loginUsername + "】发送了一封测试邮件！");
    }//GEN-LAST:event_mailTestButtonActionPerformed

    class OrderTask implements Runnable {
        @Override
        public void run() {
            logger.info("查询...");
            TicketService ticketService = TicketService.getInstance();
            LoginService loginService = LoginService.getInstance();
            RandCodeService randCodeService = RandCodeService.getInstance();

            Station fromStation = StationManager.NAME_STATION_MAP.get(fromStaionField.getText());
            Station toStation = StationManager.NAME_STATION_MAP.get(toStationField.getText());

            Date trainDate = trainDateChooser.getCalendar().getTime();

            Collection<String> passengerNames = ((CloseableLabelContainer<String>) passengersContainer).getElements();
            // 获取所有配置的乘车人
            List<Passenger> passengers = new ArrayList<>();
            for (String passengerName : passengerNames) {
                for (Passenger passenger : allPassengers) {
                    if (passengerName.equals(passenger.getPassengerName())) {
                        passengers.add(passenger);
                        break;
                    }
                }
            }

            Collection<String> trainCodesNames = ((CloseableLabelContainer<String>) trainCodesContainer).getElements();

            Collection<SeatType> seatTypes = ((CloseableLabelContainer<SeatType>) seatTypesContainer).getElements();


            LeftTicketItem[] leftTicketItems = ticketService.queryLeftTicket(trainDateChooser.getDate(),
                    fromStation.getTelecode(), toStation.getTelecode(),
                    Purpose.ADULT.getCodes(), CookieService.getInstance().getCookieData());
            logger.info("共查询到" + leftTicketItems.length + "个车次。");
            if (leftTicketItems.length == 0) {
                return;
            }

            final LinkedList leftTicketItemList = new LinkedList(Arrays.asList(leftTicketItems));
            Order order = ticketService.createOrder(leftTicketItemList, (List<Passenger>) passengers, (List<String>) trainCodesNames,
                    (List<SeatType>) seatTypes, trainDate, Purpose.ADULT.getCodes(), true);
            if (order == null) {
                logger.info("没有符合条件的车次，无法下单。");
                return;
            }

            logger.info("开始自动提交订单...");
            SubmitOrderResult submitResult;
            try {
                submitResult = ticketService.autoSubmitOrderRequest(order,
                        fromStation.getName(), toStation.getName(), CookieService.getInstance().getCookieData());
                if (!submitResult.isSubmitStatus()) {
                    logger.info("提交订单失败。");
                    return;
                }
            } catch (SessionExpiredException sex) {
                // 重新登录
                logger.info("Session失效，重新登录中...");
                loginService.logout(CookieService.getInstance().getCookieData());
                CookieService.getInstance().initCookie();
                try {
                    byte[] img = randCodeService.buildRandCodeImageBytes(CookieService.getInstance().getCookieData());
                    // 自动识别验证码
                    String rcode = UUWiseHelper.recognizeRandCode(img);
                    loginService.login(OrderConfiguration.getInstance().get12306UserName(),
                            OrderConfiguration.getInstance().get12306Password(), rcode, CookieService.getInstance().getCookieData());
                    logger.info("成功登录到12306。");
                } catch (LoginFailedException lex) {
                    logger.error("登录12306失败！原因：" + lex.getMessage());
                }
                return;
            } catch (SubmitFailedException sfe) {
                logger.error("提交订单失败！原因：" + sfe.getMessage());
                shutDownTasks();
                return;
            }

            logger.info("成功提交订单, 开始查询队列余票数量...");
            QueueCount queueCount;
            try {
                queueCount = ticketService.getQueueCountAsync(order, submitResult, CookieService.getInstance().getCookieData());
            } catch (SessionExpiredException sex) {
                // 重新登录
                logger.info("Session失效，重新登录中...");
                loginService.logout(CookieService.getInstance().getCookieData());
                CookieService.getInstance().initCookie();
                try {
                    byte[] img = randCodeService.buildRandCodeImageBytes(CookieService.getInstance().getCookieData());
                    // 自动识别验证码
                    String rcode = UUWiseHelper.recognizeRandCode(img);
                    loginService.login(OrderConfiguration.getInstance().get12306UserName(),
                            OrderConfiguration.getInstance().get12306Password(), rcode, CookieService.getInstance().getCookieData());
                    logger.info("成功登录到12306。");
                } catch (LoginFailedException lex) {
                    logger.error("登录12306失败！原因：" + lex.getMessage());
                }
                return;
            }

            if (queueCount.isQueueMoreThanRemaining()
                    || queueCount.getCountT() >= queueCount.getRemainingCount()
                    || queueCount.getRemainingCount() < passengers.size()) {
                // 余票不足时将当前车次排到最后（优先级最低），优化自动选择的成功率
                LeftTicketItem selectedItem = order.getLeftTicketItem();
                leftTicketItemList.remove(selectedItem);
                leftTicketItemList.addLast(selectedItem);
                logger.info("对不起，余票不足！");
                return;
            }

            logger.info("还有余票，开始获取验证码...");
            byte[] img = randCodeService.buildRandCodeImageBytes(CookieService.getInstance().getCookieData());
            String rcode = "";
            if (autoFillBandCodeCheckBox.isSelected()) {
                // 自动识别验证码
                rcode = UUWiseHelper.recognizeRandCode(img);
                // 自动识别验证码
                logger.info("成功识别验证码，开始确认订单...");
            } else {
                if (getCurrentBandImg() != null) {
                    // 已有验证码需要验证
                    return;
                } else {
                    setCurrentBandImg(img);
                    firePropertyChange(FILL_RAND_CODE_STATUS_NAME, IDLE, WAIT);
                    // 等待用户输入验证码
                    rcode = getCurrentRandCode();
                    setCurrentBandImg(null);
                }
            }

            // 确认订单
            boolean confirm = ticketService.confirmSingleForQueueAsys(order, submitResult, rcode, CookieService.getInstance().getCookieData());
            if (!confirm) {
                logger.info("订票确认失败。");
            } else {
                logger.info("恭喜您！订票成功！");
                orderSuccess = true;
                // 发送邮件
                sendEmail("12306订票成功", "您的【" + loginUsername + "】账号成功在12306上订票，请及时支付！");
                // shut down
                shutDownTasks();
            }
        }
    }
    
    private void sendEmail(String subject, String content) {
        //这个类主要是设置邮件   
        MailSenderInfo mailInfo = new MailSenderInfo();
        mailInfo.setMailServerHost(mailSenderServerHostField.getText().trim());
        mailInfo.setMailServerPort(mailSenderServerPortField.getText().trim());
        mailInfo.setValidate(true);
        mailInfo.setUserName(mailSenderUsernameField.getText().trim());
        mailInfo.setPassword(new String(mailSenderPasswordField.getPassword()));//您的邮箱密码 
        mailInfo.setFromAddress(mailSenderUsernameField.getText().trim());
        mailInfo.setToAddress(mailRecipientUsernameField.getText().trim());
        mailInfo.setSubject(subject);
        mailInfo.setContent(content);
        //这个类主要来发送邮件   
        SimpleMailSender sms = new SimpleMailSender();
        sms.sendTextMail(mailInfo);//发送文体格式
    }
    
    public void shutDownTasks() {
        scheduExec.shutdownNow();
        if (orderSuccess) {
            JOptionPane.showMessageDialog(this, "恭喜您！订票成功！请登录网站完成付款。", "信息", JOptionPane.INFORMATION_MESSAGE);
        }
        this.setCursor(Cursor.getDefaultCursor());
        progressBar.setIndeterminate(false);
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        addPassengerButton.setEnabled(true);
        addSeatTypeButton.setEnabled(true);
        addTrainCodeButton.setEnabled(true);
    }

    public String getCurrentRandCode() {
        return currentRandCode;
    }

    public synchronized void setCurrentRandCode(String currentRandCode) {
        this.currentRandCode = currentRandCode;
    }

    public byte[] getCurrentBandImg() {
        return currentBandImg;
    }

    public synchronized void setCurrentBandImg(byte[] currentBandImg) {
        this.currentBandImg = currentBandImg;
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addPassengerButton;
    private javax.swing.JButton addSeatTypeButton;
    private javax.swing.JButton addTrainCodeButton;
    private javax.swing.JCheckBox autoFillBandCodeCheckBox;
    private javax.swing.ButtonGroup buttonGroup;
    private javax.swing.JTextArea consoleArea;
    private javax.swing.JLabel dateLabel;
    private javax.swing.JTextField fromStaionField;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel14;
    private javax.swing.JLabel jLabel15;
    private javax.swing.JLabel jLabel16;
    private javax.swing.JLabel jLabel17;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton login2UUWButton;
    private javax.swing.JTextField mailRecipientUsernameField;
    private javax.swing.JPasswordField mailSenderPasswordField;
    private javax.swing.JTextField mailSenderServerHostField;
    private javax.swing.JTextField mailSenderServerPortField;
    private javax.swing.JTextField mailSenderUsernameField;
    private javax.swing.JButton mailTestButton;
    private javax.swing.JPanel outputPane;
    private javax.swing.JPanel passengersContainer;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JRadioButton seatHighPriorityButton;
    private javax.swing.JPanel seatTypesContainer;
    private javax.swing.JButton startButton;
    private javax.swing.JButton stopButton;
    private javax.swing.JTextField toStationField;
    private javax.swing.JPanel trainCodesContainer;
    private com.toedter.calendar.JDateChooser trainDateChooser;
    private javax.swing.JRadioButton trainHighPriorityButton;
    private javax.swing.JPasswordField uuwPasswordField;
    private javax.swing.JLabel uuwStatusLabel;
    private javax.swing.JTextField uuwUsernameField;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
}
